import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;

import java.awt.Color;
import java.awt.Point;
import java.io.File;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import svgedit.gui.commands.ChangeFillCommand;
import svgedit.gui.commands.ChangeStrokeCommand;
import svgedit.gui.commands.ChangeStrokeWidthCommand;
import svgedit.gui.commands.Command;
import svgedit.gui.commands.CommandStack;
import svgedit.gui.commands.DeleteCommand;
import svgedit.gui.commands.InsertCommand;
import svgedit.gui.commands.MoveCommand;
import svgedit.gui.commands.ResizeCommand;
import svgedit.gui.controlpoints.ControlPoint;
import svgedit.gui.controlpoints.PointControlPoint;
import svgedit.svg.SVGCircleElement;
import svgedit.svg.SVGDocument;
import svgedit.svg.SVGElement;
import svgedit.svg.SVGGroup;
import svgedit.svg.SVGLength;
import svgedit.svg.SVGPaint;
import svgedit.xml.XMLReader;

/**
 * These set of tests check all of the commands that the editor uses, Each tests
 * tests a command undo or redo method individually
 * 
 * @author Sam
 * 
 */
public class CommandTests
{

	private static SVGGroup root;
	private static SVGDocument document;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
		document = null;
		root = null;
	}

	@Before
	public void setUp() throws Exception
	{
		File f = new File("tests/simpletest.svg");
		SVGDocument doc = XMLReader.read(f, null);
		document = doc;
		root = doc.getRootGroup();
	}

	@After
	public void tearDown() throws Exception
	{
	}

	@Test
	public void testDeleteCommandUndo()
	{

		SVGElement[] elems = root.getChildren();

		// Get size
		int size = root.getChildren().length;

		// Delete all elements
		Command delCommand = new DeleteCommand(elems);
		CommandStack.getInstance().addCommand(delCommand);

		CommandStack.getInstance().undo();

		// Check size- should be all elements back
		assertEquals(size, root.getChildren().length);
	}

	@Test
	public void testDeleteCommandRedo()
	{

		SVGElement[] elems = root.getChildren();

		// Delete all elements
		Command delCommand = new DeleteCommand(elems);
		CommandStack.getInstance().addCommand(delCommand);

		// Check size- should be 0
		assertEquals(0, root.getChildren().length);

		CommandStack.getInstance().undo();

		CommandStack.getInstance().redo();

		// Check size- should be all elements back
		assertEquals(0, root.getChildren().length);
	}

	@Test
	public void testInsertUndo()
	{

		SVGCircleElement circle = new SVGCircleElement(document);

		int size = root.getChildren().length;

		// Insert element
		Command insCommand = new InsertCommand(document, circle);
		CommandStack.getInstance().addCommand(insCommand);

		CommandStack.getInstance().undo();

		// Check size - should be original size
		assertEquals(size, root.getChildren().length);
	}

	@Test
	public void testInsertRedo()
	{

		SVGCircleElement circle = new SVGCircleElement(document);

		int size = root.getChildren().length;

		// Insert element
		Command insCommand = new InsertCommand(document, circle);
		CommandStack.getInstance().addCommand(insCommand);

		CommandStack.getInstance().undo();
		CommandStack.getInstance().redo();

		// Check size- should be orignal + 1
		assertEquals(size + 1, root.getChildren().length);
	}

	@Test
	public void testMoveUndo()
	{

		SVGCircleElement circle = new SVGCircleElement(document);

		// Set shape to a posistion
		circle.getCX().setValueFromLength(
				new SVGLength(SVGLength.SVG_LENGTHTYPE_PX, 20));
		circle.getCY().setValueFromLength(
				new SVGLength(SVGLength.SVG_LENGTHTYPE_PX, 20));

		// Get shapes posistion
		Point origP = new Point((int) circle.getCX().getValue(), (int) circle
				.getCY().getValue());

		// where to move shape
		Point newP = new Point(100, 100);

		// Move element
		MoveCommand moveCommand = new MoveCommand(circle, origP);
		moveCommand.setEndPosistion(newP);
		CommandStack.getInstance().addCommand(moveCommand);

		// Undo move
		CommandStack.getInstance().undo();

		// Get shapes posistion after undo
		Point undoP = new Point((int) circle.getCX().getValue(), (int) circle
				.getCY().getValue());

		// Check point should be back to orignal same
		assertEquals(origP, undoP);
	}

	@SuppressWarnings("deprecation")
	@Test
	public void testResizeUndo()
	{

		SVGLength oldx = new SVGLength(20, SVGLength.SVG_LENGTHTYPE_PX);
		oldx.setValue(20);
		SVGLength oldy = new SVGLength(20, SVGLength.SVG_LENGTHTYPE_PX);
		ControlPoint controlPoint = new PointControlPoint(oldx, oldy);

		float fx = 10;
		float fy = 10;

		// resize element
		ResizeCommand resizeCommand = new ResizeCommand(fx, fy, controlPoint);
		CommandStack.getInstance().addCommand(resizeCommand);

		// Undo resize
		CommandStack.getInstance().undo();

		// Check point should be back to orignal same
		assertEquals((int) fx, 10);
	}

	@Test
	public void testMoveRedo()
	{

		SVGCircleElement circle = new SVGCircleElement(document);

		// Set shape to a posistion
		circle.getCX().setValueFromLength(
				new SVGLength(SVGLength.SVG_LENGTHTYPE_PX, 20));
		circle.getCY().setValueFromLength(
				new SVGLength(SVGLength.SVG_LENGTHTYPE_PX, 20));

		// Get shapes posistion
		Point origP = new Point((int) circle.getCX().getValue(), (int) circle
				.getCY().getValue());

		// where to move shape
		Point newP = new Point(100, 100);

		// Move element
		MoveCommand moveCommand = new MoveCommand(circle, origP);
		moveCommand.setEndPosistion(newP);
		CommandStack.getInstance().addCommand(moveCommand);

		CommandStack.getInstance().undo();
		CommandStack.getInstance().redo();

		// Get shapes position after redo
		Point redoP = new Point((int) circle.getCX().getValue(), (int) circle
				.getCY().getValue());

		// Check point should be back to the new point it was moved to
		assertEquals(newP, redoP);
	}

	@Test
	public void testFillUndo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Give it a colour
		circle.getFill().setRGBColor(Color.RED);

		SVGPaint newColour = new SVGPaint();
		newColour.setRGBColor(Color.BLUE);

		// Give shape a new colour
		ChangeFillCommand fillCommand = new ChangeFillCommand(circle, newColour);
		CommandStack.getInstance().addCommand(fillCommand);

		// Undo
		CommandStack.getInstance().undo();

		// Test to see if shape's colour went back to original
		assertEquals(Color.RED, circle.getFill().getRGBColor());

	}

	@Test
	public void testFillRedo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Give it a colour
		circle.getFill().setRGBColor(Color.RED);

		SVGPaint newColour = new SVGPaint();
		newColour.setRGBColor(Color.BLUE);

		// Give shape a new colour
		ChangeFillCommand fillCommand = new ChangeFillCommand(circle, newColour);
		CommandStack.getInstance().addCommand(fillCommand);

		// Undo
		CommandStack.getInstance().undo();
		CommandStack.getInstance().redo();

		// Test to see if shape's colour went back to new colour
		assertEquals(Color.BLUE, circle.getFill().getRGBColor());

	}

	@Test
	public void testStrokeUndo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Give it a stroke colour
		circle.getStroke().setRGBColor(Color.RED);

		SVGPaint newColour = new SVGPaint();
		newColour.setRGBColor(Color.BLUE);

		// Give shape a new stroke colour
		ChangeStrokeCommand strokeCommand = new ChangeStrokeCommand(circle,
				newColour);
		CommandStack.getInstance().addCommand(strokeCommand);

		// Undo
		CommandStack.getInstance().undo();

		// Test to see if shape's colour went back to original
		assertEquals(Color.RED, circle.getStroke().getRGBColor());

	}

	@Test
	public void testStrokeRedo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Give it a stroke colour
		circle.getStroke().setRGBColor(Color.RED);

		SVGPaint newColour = new SVGPaint();
		newColour.setRGBColor(Color.BLUE);

		// Give shape a new stroke colour
		ChangeStrokeCommand strokeCommand = new ChangeStrokeCommand(circle,
				newColour);
		CommandStack.getInstance().addCommand(strokeCommand);

		CommandStack.getInstance().undo();
		CommandStack.getInstance().redo();

		// Test to see if shape's colour went back to original
		assertEquals(Color.BLUE, circle.getStroke().getRGBColor());

	}

	@Test
	public void testStrokeWidthUndo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Original stroke width
		SVGLength origStroke = new SVGLength();
		origStroke.setValueFromLength(new SVGLength(
				SVGLength.SVG_LENGTHTYPE_PX, 5));

		// Give shape the stroke
		circle.getStrokeWidth().setValueFromLength(origStroke);

		// New stroke width
		SVGLength newStroke = new SVGLength();
		newStroke.setValueFromLength(new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
				10));

		// Give shape the new stroke width through command
		ChangeStrokeWidthCommand strokeCommand = new ChangeStrokeWidthCommand(
				circle, newStroke);
		CommandStack.getInstance().addCommand(strokeCommand);

		// Undo
		CommandStack.getInstance().undo();

		// Test to see if shape's stroke width went back to original
		assertEquals(circle.getStrokeWidth(), origStroke);
	}

	@Test
	public void testStrokeWidthRedo()
	{
		SVGCircleElement circle = new SVGCircleElement(document);

		// Original stroke width
		SVGLength origStroke = new SVGLength();
		origStroke.setValueFromLength(new SVGLength(
				SVGLength.SVG_LENGTHTYPE_PX, 5));

		// Give shape the stroke
		circle.getStrokeWidth().setValueFromLength(origStroke);

		// New stroke width
		SVGLength newStroke = new SVGLength();
		newStroke.setValueFromLength(new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
				10));

		// Give shape the new stroke width through command
		ChangeStrokeWidthCommand strokeCommand = new ChangeStrokeWidthCommand(
				circle, newStroke);
		CommandStack.getInstance().addCommand(strokeCommand);

		CommandStack.getInstance().undo();
		CommandStack.getInstance().redo();

		// Test to see if shape's stroke width went back to original
		assertEquals(circle.getStrokeWidth(), newStroke);

	}

}
